package mymyoux.io.sockets.clients.clientsClasses
{
	import flash.events.Event;
	import flash.utils.ByteArray;
	
	import mymyoux.io.sockets.clients.BinarySocket;
	import mymyoux.io.sockets.mapping.Telegramme;
	import mymyoux.signals.MetaSignal;
	import mymyoux.signals.Signal;

	public class MBinarySocket
	{
		protected var _socket:BinarySocket;
		protected var _id:uint;
		protected var _connected:Boolean;
		protected var _signalStatus:Signal;
		protected var _signalData:Signal;
		protected var _signalDataRoom:MetaSignal;
		protected var _signalError:Signal;
		protected var _loginTelegramme:Telegramme;
		protected var _tries:uint;
		protected var _maxTries:uint = 3;
		public function MBinarySocket(id:uint)
		{
			_id = id;
			_tries = 0;
			_loginTelegramme = new Telegramme();
			_loginTelegramme.command = Telegramme.LOGIN;
			_loginTelegramme.id = _id;
			_signalStatus = new Signal(Boolean);
			_signalData = new Signal(Telegramme);
			_signalDataRoom = new MetaSignal(Telegramme);
			_signalError = new Signal(Error);
			_socket = new BinarySocket();
			_socket.signalStatus.add(onStatut);
			_socket.signalData.add(onData);
			_socket.signalError.add(onError);
			_connected = false;
			
		}
		public function close():void
		{
			_socket.close();
		}
		public function get connected():Boolean
		{
			return _connected;
		}
		public function get port():uint
		{
			return _socket.port;
		}
		public function set port(value:uint):void
		{
			_socket.port = value;
		}
		public function get host():String
		{
			return _socket.host;
		}
		public function set host(value:String):void
		{
			_socket.host = value;
		}
		/**
		 * dispatch(error(Error));
		 */
		public function get signalError():Signal
		{
			return _signalError;
		}
		/**
		 * dispatch(connected(Boolean));
		 */
		public function get signalStatus():Signal
		{
			return _signalStatus;
		}
		/**
		 * dispatch(value(Telegramme));
		 */
		public function get signalData():Signal
		{
			return _signalData;
		}
		public function get signalDataRoom():MetaSignal
		{
			return _signalDataRoom;
		}
		
		/*
		public function get socket():Socket
		{
			return _socket.socket;
		}
		public function set socket(value:Socket):void
		{
			_socket.socket = value;
		}*/
		public function connect():void
		{
			if(!_socket.connected)
			{
				_socket.connect();
			}
		}
		public function equals(socket:MBinarySocket):Boolean
		{
			return socket!=null && socket.host === host && socket.port === port && socket === this;
		}
		public function toString():String
		{
			return "[MSocket host=\""+host+"\" port=\""+port+"\"]";
		}
		public function write(value:Telegramme):void
		{
			_socket.write(value);
		}

		protected function onData(socket:BinarySocket, value:ByteArray):void
		{
			trace("rec:"+value);
			trace(value.bytesAvailable);
			var telegramme:Telegramme;
			while(value.bytesAvailable > 0)
			{
				try
				{
					telegramme = value.readObject() as Telegramme;
					
				}catch(error:Error)
				{
					trace("CLIENT_ERROR_READING:["+error+"]");
					//if we are here, value is malformed
					break;
				}
				dataTreatment(telegramme);
			}
		
		}
		protected function dataTreatment(telegramme:Telegramme):void
		{
			trace("rec:"+telegramme);
			if(telegramme != null)
			{
				switch(telegramme.command)
				{
					//Response to login
					case Telegramme.LOGIN:
						if(telegramme.action == Telegramme.LOGIN_OK)
						{
							trace("connected");
							_connected = true;
							signalStatus.dispatch(true);
						}else
						{
							onError(_socket, new Event(Telegramme.LOGIN_ERROR));
						}
						break;
					//Data
					case Telegramme.SEND_ROOM:
					case Telegramme.GET_ROOM:
						trace("dataroom:"+telegramme);
						signalDataRoom.dispatch(telegramme.room, telegramme);
						break;
					
					default:
						signalData.dispatch(telegramme);
				}
			}
			
		}
		protected function onStatut(socket:BinarySocket, connected:Boolean):void
		{
			if(connected)
			{
				_tries = 0;
				socket.write(_loginTelegramme);
			}else
			{
				if(_connected)
				{
					
					_connected = false;
					signalStatus.dispatch(false);					
				}
				if(_tries++ < _maxTries)
				{
					_socket.connect();
				}else
				{
					onError(_socket, new Event(BinarySocket.TIMEOUT));
				}
				
				//TODO:action when disconnected
			}
		}
		protected function onError(socket:BinarySocket, error:Event):void
		{
			signalError.dispatch(new Error(error.type));
		}

	}
}